#include "DynLib.h"
#include <ut_debug.h>

#ifdef WIN32
#  define WIN32_LEAN_AND_MEAN
#  if !defined(NOMINMAX) && defined(_MSC_VER)
#	define NOMINMAX // required to stop windows.h messing up std::min
#  endif
#  include <windows.h>
#endif

CDynLib::CDynLib( const std::string & name )
{
    m_Name = name;
    m_hInst = NULL;
}

CDynLib::~CDynLib()
{
}

bool CDynLib::Load()
{
    // Log library load
    LOG(INFO)<< "Loading library " << m_Name;

    std::string name = m_Name;

#ifdef WIN32
    // Although LoadLibraryEx will add .dll itself when you only specify the library name,
    // if you include a relative path then it does not. So, add it to be sure.
    if (name.substr(name.length() - 4, 4) != ".dll")
        name += ".dll";
#elif
    // dlopen() does not add .so to the filename, like windows does for .dll
    if (name.substr(name.length() - 3, 3) != ".so")
        name += ".so";
#endif
    m_hInst = (DYNLIB_HANDLE)DYNLIB_LOAD( name.c_str() );

    if( !m_hInst )
    {
        LOG(CRITICAL) << "Could not load dynamic library " << m_Name 
            << ".System Error: " << DynlibError() << "DynLib::load";
        return false;
    }
    return true;
}

void CDynLib::Unload()
{
    // Log library unload
    LOG(INFO) << "Unloading library " << m_Name;

    if( DYNLIB_UNLOAD( m_hInst ) )
    {
        LOG(CRITICAL) << "Could not unload dynamic library " << m_Name 
            <<".System Error: " << DynlibError() << "DynLib::unload";
    }

}

void* CDynLib::GetSymbol( const std::string & strName ) const throw()
{
    return (void*)DYNLIB_GETSYM( m_hInst, strName.c_str() );
}

std::string CDynLib::DynlibError( void ) 
{
#ifdef WIN32
    LPVOID lpMsgBuf; 
    FormatMessage( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_IGNORE_INSERTS, 
        NULL, 
        GetLastError(), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPTSTR) &lpMsgBuf, 
        0, 
        NULL 
        ); 
    std::string ret = (char*)lpMsgBuf;
    // Free the buffer.
    LocalFree( lpMsgBuf );
    return ret;
#else
    return String(dlerror());
#endif
}

